package com.ittsang.service.impl;

import cn.hutool.core.date.DateTime;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.ittsang.dto.PageDTO;
import com.ittsang.dto.R;
import com.ittsang.dto.RaceDTO;
import com.ittsang.dto.UserDTO;
import com.ittsang.mapper.RaceMapper;
import com.ittsang.mapper.RaceTypeMapper;
import com.ittsang.mapper.UserClubPostsMapper;
import com.ittsang.mapper.UserRaceMapper;
import com.ittsang.pojo.Race;
import com.ittsang.pojo.RaceType;
import com.ittsang.pojo.UserClubPosts;
import com.ittsang.pojo.UserRace;
import com.ittsang.service.RaceService;
import com.ittsang.utils.RedisConstants;
import com.ittsang.utils.UserHolder;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.aop.framework.AopContext;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

@Service
@Transactional
public class RaceServiceImpl implements RaceService {

    @Resource
    private RaceMapper raceMapper;

    @Resource
    private UserRaceMapper userRaceMapper;

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    @Resource
    private RedissonClient redissonClient;

    @Resource
    private RaceTypeMapper raceTypeMapper;

    @Resource
    private UserClubPostsMapper userClubPostsMapper;

    @Override
    public R getUserRace(PageDTO pageDTO) {

        UserDTO user = UserHolder.getUser();
        List<UserRace> userRaces = userRaceMapper.getUserRace(user.getId());
        List<Race> races = new ArrayList<>();
        for (UserRace userRace : userRaces) {
            Race race = raceMapper.getUserRace(userRace.getRaceId());
            // 判断比赛的状态代码，还未编写
            dateTransform(race);
            races.add(race);
        }
        //分页操作
        return page(pageDTO, races);
    }

    @Override
    public R getAllRace(PageDTO pageDTO) {

        UserDTO user = UserHolder.getUser();

        List<Race> races = raceMapper.getAllRace();
        if (user == null) {
            for (Race race : races) {
                dateTransform(race);
            }
            //分页操作
            return page(pageDTO, races);
        }
        for (Race race : races) {
            Integer count = userRaceMapper.getUserCount(user.getId(), race.getId());
            if (count > 0) {
                race.setUserStatus(1);
            }
        }
        for (Race race : races) {
            dateTransform(race);
        }
        //分页操作
        return page(pageDTO, races);
    }

    /**
     *  时间转化并且判断
     * @param race
     */
    private void dateTransform(Race race) {
        // 创建SimpleDateFormat类型对象、 "yyyy-MM-dd HH:ss:mm.SSS"是正则式，分别表示年月日时分秒毫秒
        SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:ss:mm");
        try {
            Date now = DateTime.now();
            Date d2 = df.parse(race.getStartTime());
            if (now.getTime() < d2.getTime()) {
                race.setIsStart(0);
            }
            if (now.getTime() >= d2.getTime()) {
                Date end = df.parse(race.getEndTime());
                if (now.getTime() < end.getTime()) {
                    race.setIsStart(1);
                }
                if (now.getTime() > end.getTime()) {
                    race.setIsStart(2);
                }
            }
        } catch (ParseException e) {
            e.printStackTrace();
        }
    }


    /**
     *  分页
     * @param pageDTO
     * @param races
     * @return
     */
    private R page(PageDTO pageDTO, List<Race> races) {
        int pageNum = pageDTO.getPageNum();
        int pageSize = pageDTO.getPagesize();
        PageHelper.startPage(pageNum,pageSize);
        int skip= (pageNum-1)*pageSize;
        Page<Race> page = new Page<>(pageNum, pageSize);
        page.setTotal(races.size());
        List<Race> articleDTOList = races.stream().skip(skip)
                .limit(pageSize).collect(Collectors.toList());
        page.addAll(articleDTOList);
        return R.ok("获取成功").put("race", page).put("total", page.getTotal());
    }


    /**
     *  创建普通比赛
     * @param raceDTO
     * @return
     */
    @Override
    public R insertRace(RaceDTO raceDTO) {
        UserDTO user = UserHolder.getUser();
        raceDTO.setUserId(Math.toIntExact(user.getId()));
        raceDTO.setClubId(user.getClubId());
        return raceMapper.insertRace(raceDTO) > 0 ? R.ok("添加成功") : R.error("添加失败");
    }

    /**
     *  创建秒杀比赛
     * @param raceDTO
     * @return
     */
    @Override
    public R insertLimitRace(RaceDTO raceDTO) {
        UserDTO user = UserHolder.getUser();
        raceDTO.setUserId(Math.toIntExact(user.getId()));
        raceDTO.setClubId(user.getClubId());
        raceMapper.insertLimitRace(raceDTO);
        // 保存秒杀比赛信息
        Race race = new Race();
        race.setId(raceDTO.getId());
        race.setLimitedNum(raceDTO.getLimitedNum());
        race.setStartTime(raceDTO.getStartTime());
        race.setEndTime(raceDTO.getEndTime());

        // 保存比赛限制人数到Redis中
        stringRedisTemplate.opsForValue().set(RedisConstants.RACE_LIMIT_KEY + raceDTO.getId(), raceDTO.getLimitedNum().toString());
        return R.ok("添加成功");
    }

    @Override
    public R killRace(Integer raceId) throws ParseException {
        SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:ss:mm");
        // 1.查询比赛
        Race race = raceMapper.getUserRace(raceId);

        // 2.判断比赛是否开始
        Date now = DateTime.now();
        Date d2 = df.parse(race.getStartTime());
        Date d3 = df.parse(race.getEndTime());

        // 3.判断比赛是否结束
        if (now.getTime() > d3.getTime()) {
            // 未开始
            return R.ok("比赛已经结束！");
        }

        // 4.判断比赛报名限制人数是否充足
        if (race.getLimitedNum() < 1) {
            // 没有名额
            return R.ok("已满人！");
        }

        Long userId = UserHolder.getUser().getId();

        // 创建锁对象
        RLock lock = redissonClient.getLock("lock:order:" + userId);

        // 获取锁
        boolean isLock = lock.tryLock();

        // 判断是否获取锁成功
        if (!isLock) {
            // 获取锁失败
            return R.ok("不允许重复报名!");
        }

        try {
            // 获取代理对象事务
            RaceService proxy = (RaceService) AopContext.currentProxy();
            return proxy.createUserRace(userId,race.getId());
        } finally {
            // 释放锁
            lock.unlock();
        }
    }

    @Override
    @Transactional
    public R createUserRace(Long userId, Integer raceId) {
        // 5.一人一个名额, 查询名额
        Integer count = userRaceMapper.getUserCount(userId, raceId);

        if (count > 0) {
            // 用户已经参加
            return R.ok("用户已经参加了！");
        }

        // 扣减名额
        boolean success = raceMapper.updateRaceCount(raceId);

        if (!success) {
            // 扣减失败
            return R.error("扣减失败");
        }

        // 7.创建名额
        boolean isOk = userRaceMapper.createUserRace(userId, raceId);
        return isOk ? R.ok("参加成功！") : R.error("参加失败");
    }

    @Override
    public R getRaceType() {
        List<RaceType> raceTypes = raceTypeMapper.getRaceType();
        return R.ok("获取成功").put("raceTypes", raceTypes);
    }

    @Override
    public R getRaceById(PageDTO pageDTO) {
        List<Race> races = raceMapper.getRaceById(pageDTO.getRaceTypeId());
        for (Race race : races) {
            dateTransform(race);
        }
        return page(pageDTO, races);
    }

    @Override
    public R getAllAuditRace(PageDTO pageDTO) {
        UserDTO user = UserHolder.getUser();
        UserClubPosts userClubPosts = userClubPostsMapper.getUserRole(Math.toIntExact(user.getId()), user.getClubId());
        if (userClubPosts == null) {
            return R.error("用户无权限");
        }
        List<Race> races = raceMapper.getAllAuditRace(user.getClubId());
        for (Race race : races) {
            dateTransform(race);
        }
        //分页操作
        return page(pageDTO, races);
    }

    @Override
    public R getRaceInfoById(Integer raceId) {
        Race race = raceMapper.getRaceInfoById(raceId);
        return R.ok("获取成功").put("race", race);
    }

    @Override
    public R joinRace(Integer raceId) {
        SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:ss:mm");
        // 1.查询比赛
        Race race = raceMapper.getUserRace(raceId);

        // 2.判断比赛是否开始
        Date now = DateTime.now();
        Date d2 = null;
        try {
            d2 = df.parse(race.getStartTime());
        } catch (ParseException e) {
            throw new RuntimeException(e);
        }
        Date d3 = null;
        try {
            d3 = df.parse(race.getEndTime());
        } catch (ParseException e) {
            throw new RuntimeException(e);
        }

        // 3.判断比赛是否结束
        if (now.getTime() > d3.getTime()) {
            // 未开始
            return R.ok("比赛已经结束！");
        }
        Long userId = UserHolder.getUser().getId();
        // 4.一人一个名额, 查询名额
        Integer count = userRaceMapper.getUserCount(userId, raceId);

        if (count > 0) {
            // 用户已经参加
            return R.ok("用户已经参加了！");
        }
        // 加入名单

        boolean isOk = userRaceMapper.createUserRace(userId, raceId);
        return isOk ? R.ok("参加成功！") : R.error("参加失败");
    }


    @Override
    public R reviewedRace(Integer raceId) {
        UserDTO user = UserHolder.getUser();
        boolean i = raceMapper.reviewedRace(raceId, user.getId());
        return i ? R.ok("成功！") : R.error("失败");
    }

    @Override
    public R reviewedNoRace(Integer raceId) {
        UserDTO user = UserHolder.getUser();
        boolean i = raceMapper.reviewedNoRace(raceId, user.getId());
        return i ? R.ok("成功！") : R.error("失败");
    }

    @Override
    @Transactional
    public R quitRaceById(Integer raceId) {
        UserDTO user = UserHolder.getUser();
        Race race = raceMapper.getRace(raceId);
        // 此比赛是无人数限制
        if (race.getLimit() == 0) {
            userRaceMapper.deletedUser(raceId, user.getId());
            return R.ok("退出比赛成功");
        }
        userRaceMapper.deletedUser(raceId, user.getId());
        boolean i = raceMapper.increaseRaceCount(raceId);
        return i ? R.ok("退出比赛成功！") : R.error("退出比赛失败");
    }
}
